#include "gactiveelement.h"
#include <QtGui/QGraphicsSceneContextMenuEvent>
#include <QtSvg/QSvgRenderer>
#include <QtCore/QVector>
#include "APnMScene.h"
#include "link.h"
#include "dactiveelement.h"
#include "dcomposite.h"

QSvgRenderer GActiveElement::port;
QSvgRenderer GActiveElement::multiPort;

// based on the de e, which is a component description, create the corresponding QGraphicsItem 
GActiveElement::GActiveElement(DActiveElement* pDActiveElement, QGraphicsItem * parent)
	: GElement(pDActiveElement, parent)
{
	if (!port.isValid()) 
		port.load(QString(":/elements/port.svg"));
	if (!multiPort.isValid()) 
		multiPort.load(QString(":/elements/multiPort.svg"));

	parsePort();
	mShowName = false;
	mHitPortIndex = -1;
}

GActiveElement::~GActiveElement()
{
}

void GActiveElement::removeLink(Link *arrow)
{
	mLinks.remove(arrow);
}

void GActiveElement::addLink(Link * arrow, const QString & portName)
{
	mLinks[arrow] = portFromName(portName);
}

QList<Link*> GActiveElement::allLinks() const
{
	return mLinks.keys();
}

// use setSharedRenderer ( QSvgRenderer * renderer ) to make that port files are loaded just once.
// parse the element to get the graphics
void GActiveElement::parsePort(void)
{
	QPointF pos = centerSvg.pos();
	QRectF svgRect = centerSvg.boundingRect();	
	qreal height = svgRect.height();
	qreal width = svgRect.width();
	
	//A derived class knows its implementation details.
	//So, it not conflict with any design principles. 
	DActiveElement* da = qobject_cast<DActiveElement*>(keyDElement);
	foreach( DPort *desPort, da->ports() )
	{
		QGraphicsSvgItem* aPort = new QGraphicsSvgItem(this);
		QGraphicsTextItem* aName = new QGraphicsTextItem(this);
		aName->setPlainText(desPort->name);
		aName->setVisible(false);
		if (desPort->multiple)
			aPort->setSharedRenderer(&multiPort);
		else
			aPort->setSharedRenderer(&port);
		aPort->setZValue( centerSvg.zValue()+0.1);
		QPointF pCenter = aPort->boundingRect().center();
		QPointF location;
		if (desPort->direction == "in") {
			location.setY( height*(desPort->ordinal+1)/(da->sumInPorts()+1) );
			location.setX(0);
			aName->setPos(pos+location-aName->boundingRect().bottomRight()-QPointF(8,0));
		}
		else{
			location.setY( height*(desPort->ordinal+1)/(da->sumOutPorts()+1) );
			location.setX( width );
			aName->setPos(pos+location-aName->boundingRect().bottomLeft());
		}
		location = pos + location - pCenter;	
		aPort->setPos( location);

		addToGroup(aPort);
		mPorts.append(aPort);
		mPortsName.append(aName);
	}
}

//If the Graphics is a hited port in this GraphicsGroup.
//If it is, hold its index in mHitPortIndex.
bool GActiveElement::isHitPort(QGraphicsSvgItem* hitedGraphics)
{
	mHitPortIndex = mPorts.indexOf(hitedGraphics);
	return (mHitPortIndex != -1) ? true : false;
}

QGraphicsSvgItem* GActiveElement::portFromName(const QString portName) const
{
	for (int index = 0; index<mPorts.size(); ++index) {
		if (portName == mPortsName[index]->toPlainText()) 
			return mPorts[index];
	}
	return NULL;
}

QString GActiveElement::portName(QGraphicsSvgItem* port) const
{
	int index = mPorts.indexOf(port);
	if (index == -1) return QString();
	return mPortsName[index]->toPlainText();
}

QString GActiveElement::portDirection(QGraphicsSvgItem* hitedGraphics) const
{
	int index = mPorts.indexOf(hitedGraphics);
	if (index == -1) return QString();
	DActiveElement* da = qobject_cast<DActiveElement*>(keyDElement);
	return da->ports()[index]->direction;
}

QVariant GActiveElement::itemChange(GraphicsItemChange change, const QVariant &value)
{
	if (change == QGraphicsItem::ItemPositionChange) {
		foreach (Link *arrow, mLinks.keys()) {
			arrow->updatePosition();
		}
	}

	return value;
}

void GActiveElement::flipPortNameVisible()
{
	mShowName = !mShowName;
	foreach(QGraphicsTextItem* item, mPortsName)
		item->setVisible(mShowName);
}

QString GActiveElement::getSubFilePath() const
{
	DComposite* dc = qobject_cast<DComposite*>(keyDElement);
	if (dc) 
		return dc->getFilePath();
	else
		return QString();
}